//
// Created by denglibin on 2021/5/6.
//

#include "QuickDemo.h"

static String winName = "LightAdjustment";

/**
  * 回调
  * @param pos
  * @param userdata
  */
static void onLightness(int pos, void* userdata);
static void onContrast(int pos, void* userdata);

QuickDemo::QuickDemo(){

}

void QuickDemo::colorSpaceDemo(Mat &mat) {
    Mat gray, hsv;
    cvtColor(mat, hsv, COLOR_BGR2HSV);//色调（H），饱和度（S），明度（V）
    cvtColor(mat, gray, COLOR_BGR2GRAY); //转成灰度图像
    //imshow("source", mat);
    //imshow("HSV", hsv);
    imshow("GRAY", gray);
    //imwrite("../img/hsv.png", hsv);
    //imwrite("../img/gray.png", gray);
}

void QuickDemo::matCreationDemo(Mat &mat) {
    Mat m1, m2;
    m1 = mat.clone(); //克隆
    mat.copyTo(m2);

    imshow("m1", m1);
    imshow("m2", m2);

    //创建空白图像
    //Mat m3 = Mat::zeros(Size(8, 8), CV_8UC1); // 8 * 8 单通道
    Mat m3 = Mat::zeros(Size(512, 512), CV_8UC3); //  三通道
    m3 = Scalar(255, 12, 234); //三个通道全部设置为127
    //std::cout << "width:" << m3.cols << "; height:" << m3.rows << "; channels:" << m3.channels() << endl;
    //std::cout << m3 << std::endl;
    imshow("my", m3);

}

void QuickDemo::pixelVisitDemo(Mat& mat){
    int width = mat.cols;
    int height = mat.rows;

    int channels = mat.channels();
/*    int pv;
    for(int row = 0; row < height; row++){
        for(int col = 0; col < width; col++){
            if(channels == 1){ //灰度图像
                pv = mat.at<uchar>(row, col);
                mat.at<uchar>(row, col) = 255 - pv;
            }
            if(channels == 3){ // 彩色图像
                Vec3b bgr  = mat.at<Vec3b>(row, col);
                mat.at<Vec3b>(row, col)[0] = 255 - bgr[0];
                mat.at<Vec3b>(row, col)[1] = 255 - bgr[1];
                mat.at<Vec3b>(row, col)[2] = 255 - bgr[2];
            }
        }
    }*/
    for(int row = 0; row < height; row++){
        uchar* current_row = mat.ptr(row);//当前行指针(当前行第0个元素)
        for(int col = 0; col < width; col++){
            if(channels == 1){ //灰度图像
                *current_row++ = 255 - *current_row;
            }
            if(channels == 3){ // 彩色图像
                *current_row++ = 255 - *current_row;
                *current_row++ = 255 - *current_row;
                *current_row++ = 255 - *current_row;
            }
        }
    }
    imshow("pixel", mat);
}

void QuickDemo::pixelOperate(Mat& mat){
    Mat dist;
    //dist = mat + Scalar(50, 50, 50); //像素通道值都加50，变亮
   // dist = mat / Scalar(2, 2, 2); //像素通道值都除以2，变暗

    //multiply(mat,Scalar(2, 2, 2), dist); //像素通道值都乘以2，变亮
    //divide(mat, Scalar(2, 2, 2), dist); //除法
    //add(mat,Scalar(50, 50, 50), dist); //加
    subtract(mat, Scalar(50, 50, 50), dist); //减
    imshow("source", mat);
    imshow("operate", dist);
}

void QuickDemo::trackBarDemo(Mat& mat){

    namedWindow(winName, WINDOW_AUTOSIZE);

    int lightness = 50;
    int contrast_value = 100;

    createTrackbar("Light Bar:", winName, &lightness, 100, onLightness, (void*)(&mat)); //调整亮度
    createTrackbar("Contrast Bar:", winName, &contrast_value, 200, onContrast, (void*)(&mat)); //调整对比度
    onLightness(lightness, &mat);
}

void QuickDemo::colorStyle(Mat& mat){
    Mat dist;
    int index = 0;
    while (true){
        int c = waitKey(500);
        if(c == 27){
            return;
        }
        applyColorMap(mat, dist, index++); // ColormapTypes 枚举类型 COLORMAP_AUTUMN，COLORMAP_BONE，COLORMAP_WINTER...
        if(index >21) {
            index = 0;
        }
        imshow("color style", dist);
    }
}

void QuickDemo::bitWiseDemo(Mat& mat){
    Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
    Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
    rectangle(m1, Rect(100, 100, 80, 80),
              Scalar(255, 255, 0), -1, LINE_8,0);
    rectangle(m2, Rect(150, 150, 80, 80),
              Scalar(0, 255, 255), -1, LINE_8,0);
    imshow("m1", m1);
    imshow("m2", m2);
    Mat dist;
    bitwise_and(m1, m2, dist); //与操作
    imshow("m1_and_m2", dist);

    bitwise_or(m1, m2, dist); //or操作
    imshow("m1_or_m2", dist);

    bitwise_xor(m1, m2, dist); //异或
    imshow("m1_xor_m2", dist);

    bitwise_not(mat, dist); //not操作
    imshow("mat not", dist);
}

void QuickDemo::channelsDemo(Mat& mat){
    std::vector<Mat> mv;
    split(mat, mv); //通道分离
    imshow("blue_channel", mv[0]);//蓝色单通道
    imshow("green_channel", mv[1]);//绿色单通道
    imshow("red_channel", mv[2]);//红色单通道

    Mat dist;
    mv[1] = 0; //绿色通道置为0
    //mv[2] = 0; //红色通道置为0
    mv[0] = 0; //蓝色通道置为0
    merge(mv, dist); //通道合并
    imshow("color", dist);
    int from_to []= {0,1,  1,2,   2,0}; //通道混合
    mixChannels(&mat, 1, &dist, 1, from_to, 3);
    imshow("mix", dist);
}


void QuickDemo::inRangeDemo(Mat& mat){

    Mat mask;
    //范围内的颜色置为白色，其他置为黑色
    inRange(mat, Scalar(230, 230, 230), Scalar(255, 255, 255), mask);

    Mat redBack = Mat::zeros(mat.size(), mat.type());
    redBack = Scalar(40, 40, 200);
    bitwise_not(mask, mask);//取反
    mat.copyTo(redBack, mask); //拷贝，mask为0像素点不会拷贝，其他会拷贝
    imshow("mat", mat);
    imshow("redBack", redBack);
}

void QuickDemo::pixelStatistic(Mat& mat){
    double minV, maxV;
    Point  minLoc, maxLoc;
    std::vector<Mat> v;
    split(mat, v); // 通道分离
    for(int i = 0; i < v.size(); i++){
        //最大值，最小值统计
        minMaxLoc(v[i], &minV, &maxV, &minLoc, &maxLoc, Mat());
        std::cout << "No.Channel:" << i << "; min value:" << minV << "; max value:" << maxV << std::endl;
    }

    //均值，方差（方差为0表示纯色）
    Mat mean, stdDev;
    meanStdDev(mat, mean, stdDev);
    std::cout << "means:" << mean << std::endl;
    std::cout << "stdDev:" << stdDev << std::endl;

}

void QuickDemo::drawDemo(Mat& mat){
    Rect rect;
    rect.x = 200;
    rect.y = 200;
    rect.width = 100;
    rect.height = 100;
    Mat bg = Mat::zeros(mat.size(), mat.type());

    //绘制矩形,thickness参数:线宽（小于0则填充）
    rectangle(bg, rect, Scalar(0, 0, 255), -1, 8, 0);
    //绘制圆
    circle(bg, Point(200, 400), 30, Scalar(255, 0, 0), 2, LINE_8, 0);
    //线
    line(bg, Point(0, 0), Point(100, 100), Scalar(0, 255, 0), 5, LINE_8, 0);

    //椭圆
    RotatedRect rrt;
    rrt.center = Point(200, 200);
    rrt.size = Size(100, 200);
    rrt.angle = 90.0f;
    ellipse(bg, rrt, Scalar(0, 255, 255), 2, LINE_AA); //LINE_AA 抗锯齿

    Mat dist;
    addWeighted(mat, 0.5, bg, 0.5, 0, dist);
    imshow("draw", bg);

}

void QuickDemo::randomDraw(Mat& mat){
    Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
    int w = canvas.cols;
    int h = canvas.rows;
    //随机
    RNG rng(12345);
    while (true){
        int c = waitKey(300);
        if(c == 27) {
            break;
        }
        int x1 = rng.uniform(0, w);
        int y1 = rng.uniform(0, h);

        int x2 = rng.uniform(0, w);
        int y2 = rng.uniform(0, h);

        int r = rng.uniform(0, 255);
        int g = rng.uniform(0, 255);
        int b = rng.uniform(0, 255);
        //canvas = Scalar(0, 0, 0); //清除
        line(canvas, Point(x1, y1), Point(x2, y2),
             Scalar(b, g, r),
             1, LINE_AA, 0);
        imshow("randomDraw", canvas);
    }

}

void QuickDemo::drawPolygon(Mat& mat){
    Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
    Point p1(100, 100);
    Point p2(350, 100);
    Point p3(450, 280);
    Point p4(320, 450);
    Point p5(80, 400);
    vector<Point> pts;
    pts.push_back(p1);
    pts.push_back(p2);
    pts.push_back(p3);
    pts.push_back(p4);
    pts.push_back(p5);

    //多边形，isClose: 是否闭合; thickness不能设置成负数
    //polylines(canvas, pts, true, Scalar(0, 255, 255), 5,LINE_AA, 0);
    //填充
    //fillPoly(canvas, pts, Scalar(255, 0, 0), LINE_AA, 0);

    vector<vector<Point>> contours;
    contours.push_back(pts);
    //绘制 轮廓,可以设置thickness线宽 为负数来进行填充
    //第三个参数 contourIdx绘制第几个，-1表示绘制全部
    drawContours(canvas, contours, -1, Scalar(0, 255, 0), -1, LINE_AA);

    imshow("polygon", canvas);
}

void QuickDemo::normalizedDemo(Mat& mat){
    Mat dist;
    cout << mat.type() << endl;
    //转成32位浮点数
    mat.convertTo(dist, CV_32F);
    cout << dist.type() << endl;
    //标准化到0-1之间
    normalize(dist, dist, 1.0f, 0, NORM_MINMAX);
    imshow("normalized", dist);

    //转回来
    normalize(dist, dist, 255, 0, NORM_MINMAX);
    dist.convertTo(dist, CV_8U);
    cout << dist.type() << endl;
    imshow("un_normalized", dist);
}

void QuickDemo::resizeDemo(Mat& mat){
    Mat zoomin, zoomax;
    int h = mat.rows;
    int w = mat.cols;
    resize(mat, zoomin,  Size(w/2, h/2),0, 0, INTER_LINEAR);
    resize(mat, zoomax,  Size(w * 1.5f, h * 1.5),0, 0, INTER_LINEAR);
    imshow("zoomin", zoomin);
    imshow("zoomax", zoomax);
}

void QuickDemo::flipDemo(Mat &mat) {
    Mat dist;
    //flip(mat, dist, 0); //上下翻转
    //flip(mat, dist, 1); //左右翻转
    flip(mat, dist, -1); //180度旋转
    imshow("flip", dist);
}

void QuickDemo::rotateDemo(Mat& mat){
    Mat dist, m;
    int w = mat.cols;
    int h = mat.rows;
    //旋转矩阵
    m = getRotationMatrix2D(Point2f(w/2, h/2), 45, 1.0);
    double cos = abs(m.at<double>(0, 0));
    double sin = abs(m.at<double>(0, 1));
    int newW = cos*w + sin*h;
    int newH = sin*w + cos*h;
    m.at<double>(0, 2) +=  (newW/2 - w/2);
    m.at<double>(1, 2) += (newH/2 - h/2);
    //仿射变换
    warpAffine(mat, dist, m, Size(newW, newH), INTER_LINEAR, 0, Scalar(255, 0, 0));
    imshow("rotate", dist);
}

void QuickDemo::videoDemo(Mat& mat){
    //VideoCapture capture(0); //摄像头
    VideoCapture capture("C:/Users/mdjro/Desktop/123.mp4");
    double width = capture.get(CAP_PROP_FRAME_WIDTH);
    double height = capture.get(CAP_PROP_FRAME_HEIGHT);
    double count = capture.get(CAP_PROP_FRAME_COUNT);
    double fps = capture.get(CAP_PROP_FPS);
    cout << "width:" << width <<"; height:" << height <<"; count:" << count << "; fps:" << fps << endl;
    VideoWriter writer("C:/Users/mdjro/Desktop/test.mp4", capture.get(CAP_PROP_FOURCC),fps, Size(width, height), true);
    Mat frame;
    while (true){
        capture.read(frame);
        //flip(frame, frame, 1); //左右翻转一下
        if(frame.empty()){
            cout << "frame is empty" << endl;
            break;
        }
        colorSpaceDemo(frame);
        imshow("frame", frame);
        writer.write(frame);
        int c = waitKey(10);
        if(c == 27){
            break;
        }
    }
    capture.release();
    writer.release();
}

void QuickDemo::showHistogram(Mat& mat){
    //三通道分离
    vector<Mat> bgr_plane;
    split(mat, bgr_plane);
    //定义参数变量
    const int channels[1] = {0};
    const int bins[1] = {256};//灰度级别
    float hranges[2] = {0, 255};
    const float* ranges[1] = {hranges};
    Mat b_hist;
    Mat g_hist;
    Mat r_hist;
    // 计算blue, green, red通道的直方图
    //参数:数据, 图像数量，通道， mask，输出，1维直方图，
    calcHist(&bgr_plane[0], 1, channels, Mat(), b_hist, 1, bins, ranges);
    calcHist(&bgr_plane[1], 1, channels, Mat(), g_hist, 1, bins, ranges);
    calcHist(&bgr_plane[2], 1, channels, Mat(), r_hist, 1, bins, ranges);
    //显示直方图
    int hist_w = 512;
    int hist_h = 400;
    int bin_w = cvRound((double)hist_w/bins[0]);
    //创建画布
    Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
    //标准化,使数值都在画布高度范围内
    normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    //绘制直方图曲线
    for(int i = 1; i < bins[0]; i++){
        line(histImage,
             Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
             Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i ))),
             Scalar(255, 0, 0), 1, LINE_8, 0 );
         line(histImage,
             Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
             Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i ))),
             Scalar(0, 255, 0), 1, LINE_8, 0 );
         line(histImage,
             Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
             Point(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i ))),
             Scalar(0, 0, 255), 1, LINE_8, 0 );
    }
    imshow("img", mat);
    imshow("histogram", histImage);

}


 void onLightness(int pos, void* userdata){
    Mat mat = *(Mat*)userdata;
    pos -= 50;
    Mat m = Mat::zeros(mat.size(), mat.type());
    Mat dist;
    addWeighted(mat, 1.0F, m, 0, pos, dist);
    imshow(winName, dist);
}

 void onContrast(int pos, void* userdata){
    Mat mat = *(Mat*)userdata;
    Mat m = Mat::zeros(mat.size(), mat.type());
    Mat dist;
    double contrast = (double)pos / 100.0f;
    addWeighted(mat, contrast, m, 0, 0, dist);
    imshow(winName, dist);
}

